The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Changes 139143
MANIFEST 03
MANIFEST.SKIP 41
META.yml 28
Makefile.PL 26
README 1019
lib/Gitalist/Controller/Root.pm 120
lib/Gitalist/Git/CollectionOfRepositories.pm 11
lib/Gitalist/Git/HasUtils.pm 01
lib/Gitalist/Git/Head.pm 69
lib/Gitalist/Git/Object.pm 58
lib/Gitalist/Git/Repository.pm 1114
lib/Gitalist/Git/Serializable.pm 08
lib/Gitalist/Git/Tag.pm 79
lib/Gitalist/Git/Types.pm 139
lib/Gitalist.pm 215
root/ref/blob.tt2 22
root/repository/search.tt2 19
root/search_help.tt2 11
root/static/css/core.css 16
script/gitalist_app.psgi 019
t/02git_Repository.t 043
t/02git_object.t 081
t/json_view.t 039
24 files changed (This is a version diff) 196504
@@ -1,188 +1,192 @@
 This file documents the revision history for Perl extension Gitalist.
 
+0.003002 2011-05-22
+  - Add JSON serialization and expose via .json (Tomas Doran).
+  - Provide .psgi for Plack goodness (Francoise Dehinbo).
+
 0.003001 2011-03-13
-   - Reinstate FromDirectory in model.
-   - Drop unneeded deps in Makefile.PL.
-   - Add support for multiple repos with the same name (Jose Luis Martinez).
-   - Make paging work for history (Lian Wan Situ),
-   - Respect paging.log config settings.
+  - Reinstate FromDirectory in model.
+  - Drop unneeded deps in Makefile.PL.
+  - Add support for multiple repos with the same name (Jose Luis Martinez).
+  - Make paging work for history (Lian Wan Situ),
+  - Respect paging.log config settings.
 
 0.002009 2011-03-06
-   - Document the available configuration options.
-   - Provide switch in config for forcing recursive repo searching.
-   - Assume UTF8 encoded blobs.
+  - Document the available configuration options.
+  - Provide switch in config for forcing recursive repo searching.
+  - Assume UTF8 encoded blobs.
 
 0.002008 2011-02-26
-   - Add the ability to provide a whitelist of repos.
-   - Add support for export-ok config option.
-   - Ignore ancient/malformed tags.
-   - Use the correct perl binary we installed against (Tom Hukins)
+  - Add the ability to provide a whitelist of repos.
+  - Add support for export-ok config option.
+  - Ignore ancient/malformed tags.
+  - Use the correct perl binary we installed against (Tom Hukins)
 
 0.002007 2011-02-19
-   - Add support for recursively searching for git repos (Dipesh Patel)
-   - Cleaned up model code in Gitalist::Git:: (Zachary Stevens)
-   - Improve POD mark-up, some typos (Lars Dɪᴇᴄᴋᴏᴡ 迪拉斯)
-   - Regenerated README and fixed tests for bootstrapped checkouts.
-   - Add Test::Exception dep.
+  - Add support for recursively searching for git repos (Dipesh Patel)
+  - Cleaned up model code in Gitalist::Git:: (Zachary Stevens)
+  - Improve POD mark-up, some typos (Lars Dɪᴇᴄᴋᴏᴡ 迪拉斯)
+  - Regenerated README and fixed tests for bootstrapped checkouts.
+  - Add Test::Exception dep.
 
 0.002006 2010-10-17
-   - Added notes regarding slash encoding in Catalyst
-   - Fixed typo in core.css
-   - Updated formatting in Gitalist.pm
-   - Modified README with more details on FCGI deployment with Apache
-   - Fix broken env includes in script/gitalist*.pl.
+  - Added notes regarding slash encoding in Catalyst
+  - Fixed typo in core.css
+  - Updated formatting in Gitalist.pm
+  - Modified README with more details on FCGI deployment with Apache
+  - Fix broken env includes in script/gitalist*.pl.
 
 0.002005 2010-08-13
-    - Limit the number of branches/tags listed by default.
+  - Limit the number of branches/tags listed by default.
 
 0.002004 2010-08-02
-    - Fix misnamed variable which was giving a syntax error in
-      Gitalist::Controller::Fragment::Ref.
-    - Fix blame view to display syntax highlighted blobs correctly
-      instead of outputting raw HTML.
+  - Fix misnamed variable which was giving a syntax error in
+    Gitalist::Controller::Fragment::Ref.
+  - Fix blame view to display syntax highlighted blobs correctly
+    instead of outputting raw HTML.
 
 0.002003 2010-08-02
-    - Fix for distribution not including script/env causing Makefile.PL
-      and scripts to die.
+  - Fix for distribution not including script/env causing Makefile.PL
+    and scripts to die.
 
 0.002002 2010-08-01
-    - Fix dist packaging issues.
+  - Fix dist packaging issues.
 
 0.002001 2010-07-03
-    - Fix for loadCommitInfo.
-    - Fix tests to work with local-libbery.
-    - Correct example link and FCGI script.
-    - Bumping version and updated Changes appropriately.
-    - Throttle the commit info loading.
-    - Update bootstrapping for local::lib 1.006000.
-    - Fixed author_* barewords in Makefile.PL.
-    - Handle merges in the diff view.
-    - Add script/{bootstrap.pl,env} to MANIFEST.SKIP.
+  - Fix for loadCommitInfo.
+  - Fix tests to work with local-libbery.
+  - Correct example link and FCGI script.
+  - Bumping version and updated Changes appropriately.
+  - Throttle the commit info loading.
+  - Update bootstrapping for local::lib 1.006000.
+  - Fixed author_* barewords in Makefile.PL.
+  - Handle merges in the diff view.
+  - Add script/{bootstrap.pl,env} to MANIFEST.SKIP.
 
 0.001008 2010-06-03
-   - Add a requires_external_bin for the git command so we won't try running
-     tests unless it's present.
-   - Remove MooseX::MultiMethods as it has been broken by a recent Moose
-     change. The new code is smaller and will be faster.
-   - Add diagnostics to the tests to print out the version of git that
-     people are using.
-   - Make tests which commonly fail with older/different versions of git
-     fail with the output of their git command to make debugging the tests
-     from automated reports possible.
+  - Add a requires_external_bin for the git command so we won't try running
+    tests unless it's present.
+  - Remove MooseX::MultiMethods as it has been broken by a recent Moose
+    change. The new code is smaller and will be faster.
+  - Add diagnostics to the tests to print out the version of git that
+    people are using.
+  - Make tests which commonly fail with older/different versions of git
+    fail with the output of their git command to make debugging the tests
+    from automated reports possible.
 
 0.001007 2010-05-15
-    - Set the use_request_uri_for_path configuration variable to be compatible
-      with Catalyst 5.80024.
+  - Set the use_request_uri_for_path configuration variable to be compatible
+    with Catalyst 5.80024.
 
 0.001006 2010-05-13
-    - Fix Catalyst::Action::REST dependency (there wasn't one previously)
-    - Depend on latest Catalyst::View::TT due to a previous bad version
-      breaking things.
-    - Add render_die => 1 in the View::TT config as we do want real exceptions
-      when we call ->render ourselves.
+  - Fix Catalyst::Action::REST dependency (there wasn't one previously)
+  - Depend on latest Catalyst::View::TT due to a previous bad version
+    breaking things.
+  - Add render_die => 1 in the View::TT config as we do want real exceptions
+    when we call ->render ourselves.
 
 0.001005 2010-05-11
-    - Depend on latest MX::Declare to fix issues for people who upgrade
-      MooseX::Types::Structured to a newer version.
-    - Add some padding below, so file icons are not chopped off
-    - Updated favicon to cope with dark grey backgrounds
+  - Depend on latest MX::Declare to fix issues for people who upgrade
+    MooseX::Types::Structured to a newer version.
+  - Add some padding below, so file icons are not chopped off
+  - Updated favicon to cope with dark grey backgrounds
 
 0.001004 2010-05-06
-    - Remove unneeded dependencies:
-      - XML::OPML::SimpleGen
-      - XML::Atom
-      - XML::RSS
-    - Fixed author_* barewords in Makefile.PL so that users checking out from
-      git without the author modules works correctly.
+  - Remove unneeded dependencies:
+  - XML::OPML::SimpleGen
+  - XML::Atom
+  - XML::RSS
+  - Fixed author_* barewords in Makefile.PL so that users checking out from
+    git without the author modules works correctly.
 
 0.001003 2010-04-21
-    - Added folder / file icons in tree view (Foxtons)
-    - Added favicon
-    - Fix for non uri_for hard coded links for running at not root locations.
-      (RT#56747)
+  - Added folder / file icons in tree view (Foxtons)
+  - Added favicon
+  - Fix for non uri_for hard coded links for running at not root locations.
+    (RT#56747)
 
 0.001002 2010-04-20
-    - Fix link for the project_index action.
-    - Add missing images to MANIFEST.
+  - Fix link for the project_index action.
+  - Add missing images to MANIFEST.
 
 0.001001 2010-04-15
-    - Bumping version number to a format I understand, thanks to mst for
-      pointing me in the right direction and t0m for the new number.
-    - Cleaned up the search results - removed search from the homepage as
-      wasn't working (Foxtons).
-    - Provide a link for an atom entry. switch mode=xml to type=xhtml (Brian
-      Cassidy).
+  - Bumping version number to a format I understand, thanks to mst for
+    pointing me in the right direction and t0m for the new number.
+  - Cleaned up the search results - removed search from the homepage as
+    wasn't working (Foxtons).
+  - Provide a link for an atom entry. switch mode=xml to type=xhtml (Brian
+    Cassidy).
 
 0.000006.1 2010-04-14
-    - Documentation fixes for the --repo-dir flag (Dagfinn Ilmari Mannsåker).
+  - Documentation fixes for the --repo-dir flag (Dagfinn Ilmari Mannsåker).
 
 0.000006 2010-04-10
-    - Major frontend redesign, thanks to ranguard and the web designers at
-      Foxtons for making this happen.
-    - Major URI overhaul, Gitalist has gone from old gitweb style CGI
-      parameters to proper URIs, however the old URIs are still supported
-      and will redirect appropriately (Tomas Doran).
-    - With the URI overhaul also came breaking up actions into fragments
-      for use with Catalyst::View::Component::SubInclude.
-    - BIG BREAKING CHANGE - Gitalist::Model::GitRepos has been renamed
-      Gitalist::Model::CollectionOfRepos. You need to fix your config and
-      if you have actually installed Gitalist - remove the old model file.
-    - Bump required version of Git::PurePerl for Encoding fixes.
-    - Fix Makefile.PL to not need release deps when checking out of Git.
+  - Major frontend redesign, thanks to ranguard and the web designers at
+    Foxtons for making this happen.
+  - Major URI overhaul, Gitalist has gone from old gitweb style CGI
+    parameters to proper URIs, however the old URIs are still supported
+    and will redirect appropriately (Tomas Doran).
+  - With the URI overhaul also came breaking up actions into fragments
+    for use with Catalyst::View::Component::SubInclude.
+  - BIG BREAKING CHANGE - Gitalist::Model::GitRepos has been renamed
+    Gitalist::Model::CollectionOfRepos. You need to fix your config and
+    if you have actually installed Gitalist - remove the old model file.
+  - Bump required version of Git::PurePerl for Encoding fixes.
+  - Fix Makefile.PL to not need release deps when checking out of Git.
 
 0.000005 2010-01-09
-    - Require Git::PurePerl for Win32 compatibility.
-    - Switch to IPC::Run::start for streamed mode, fixing RT#52658
-      and the tests with FreeBSD.
-    - Require new FCGI release in the FCGI script for upstream bug fixes.
-    - Fix tests with older versions of git.
-    - Allow the model to be configured with a list of repositories rather
-      then a directory containing repositories.
-    - Fix syntax highlighting CSS link
-    - Add per line link for previous version of a line in blame.
+  - Require Git::PurePerl for Win32 compatibility.
+  - Switch to IPC::Run::start for streamed mode, fixing RT#52658
+    and the tests with FreeBSD.
+  - Require new FCGI release in the FCGI script for upstream bug fixes.
+  - Fix tests with older versions of git.
+  - Allow the model to be configured with a list of repositories rather
+    then a directory containing repositories.
+  - Fix syntax highlighting CSS link
+  - Add per line link for previous version of a line in blame.
 
 0.000004 2009-12-19
-    - Support being able to pass a list of repositories to view via
-      configuration, rather than having a static directory.
-    - Installation and configuration documentation has been enhanced.
-    - Project has been renamed Repository to correspond with normal git
-      terminology.
-    - Repos has been refactored into a CollectionOfRepositories role
-      and two differnet concrete implementations (the Catalyst model
-      chooses which type to build based on the config).
-    - Remove all tabs and fix no tabs test (Dagfinn Ilmari Mannsåker)
-    - Decode getpwuid values correctly (Dagfinn Ilmari Mannsåker)
-    - Generate correct provides information in META.yml so that search.cpan
-      indexes the classes contained in Gitalist correctly.
-    - Dropped the dependency on File::Stat::ModeString
+  - Support being able to pass a list of repositories to view via
+    configuration, rather than having a static directory.
+  - Installation and configuration documentation has been enhanced.
+  - Project has been renamed Repository to correspond with normal git
+    terminology.
+  - Repos has been refactored into a CollectionOfRepositories role
+    and two differnet concrete implementations (the Catalyst model
+    chooses which type to build based on the config).
+  - Remove all tabs and fix no tabs test (Dagfinn Ilmari Mannsåker)
+  - Decode getpwuid values correctly (Dagfinn Ilmari Mannsåker)
+  - Generate correct provides information in META.yml so that search.cpan
+    indexes the classes contained in Gitalist correctly.
+  - Dropped the dependency on File::Stat::ModeString
 
 0.000003 2009-12-09
-    - Officially switch repository to Shadowcat
-    - Officially switch bug tracker to rt.cpan.org
-    - Start streamlining and generally rejiging the layout.
-    - Hacked in syntax highlighting to the blame view.
-    - Further tweaks to the blame view, making it more informative.
-    - Move all POD below the code, for ::Repo and ::Project.
+  - Officially switch repository to Shadowcat
+  - Officially switch bug tracker to rt.cpan.org
+  - Start streamlining and generally rejiging the layout.
+  - Hacked in syntax highlighting to the blame view.
+  - Further tweaks to the blame view, making it more informative.
+  - Move all POD below the code, for ::Repo and ::Project.
 
 0.000002 2009-12-06
-   - Add documentation about how to configure a Gitalist instance.
-   - Fix so that invalid repository directory will be detected at application
-     startup and a helpful error message will be displayed.
-   - Add --repos_dir command line parameter to all of the scripts which can
-     be used to force the repository directory, overriding config and
-     environment.
-   - Add GITALIST_REPOS_DIR environment variable which will determine the
-     repository path (overriding normal config) if set.
-   - Change so that no default repos path is in the config when installed from
-     CPAN (when checked out of git, behavior of browsing AppDir/../ is
-     maintained).
-   - Do not allow directory traversal via the p param.
-
-0.000001
-   - No changes since last dev release.
-
-0.000000_02  UNRELEASED
-   - Fixed history action, other minor cleanups.
-
-0.000000_01  UNRELEASED
-   - Initial release to CPAN
+  - Add documentation about how to configure a Gitalist instance.
+  - Fix so that invalid repository directory will be detected at application
+    startup and a helpful error message will be displayed.
+  - Add --repos_dir command line parameter to all of the scripts which can
+    be used to force the repository directory, overriding config and
+    environment.
+  - Add GITALIST_REPOS_DIR environment variable which will determine the
+    repository path (overriding normal config) if set.
+  - Change so that no default repos path is in the config when installed from
+    CPAN (when checked out of git, behavior of browsing AppDir/../ is
+    maintained).
+  - Do not allow directory traversal via the p param.
+
+0.000001 2009-12-02
+  - No changes since last dev release.
+
+0.000000_02 2009-12-01
+  - Fixed history action, other minor cleanups.
+
+0.000000_01 2009-11-25
+  - Initial release to CPAN
@@ -46,6 +46,7 @@ lib/Gitalist/Git/Object/HasTree.pm
 lib/Gitalist/Git/Object/Tag.pm
 lib/Gitalist/Git/Object/Tree.pm
 lib/Gitalist/Git/Repository.pm
+lib/Gitalist/Git/Serializable.pm
 lib/Gitalist/Git/Tag.pm
 lib/Gitalist/Git/Types.pm
 lib/Gitalist/Git/Util.pm
@@ -159,6 +160,7 @@ root/static/i/logo.png
 root/static/js/jquery.min.js
 root/static/js/site.js
 root/wrapper.tt2
+script/gitalist_app.psgi
 script/gitalist_cgi.pl
 script/gitalist_create.pl
 script/gitalist_fastcgi.pl
@@ -181,6 +183,7 @@ t/author/notabs.t
 t/author/pod.t
 t/author/podcoverage.t
 t/gitalist.conf
+t/json_view.t
 t/lib/repositories/bare.git/config
 t/lib/repositories/bare.git/description
 t/lib/repositories/bare.git/HEAD
@@ -12,7 +12,4 @@ Makefile\.old$
 \.shipit$
 script/bootstrap.pl
 script/env
-script/cpan-install
-local-lib5
-.*[~#]
-.*swp
+
@@ -24,7 +24,7 @@ no_index:
 provides:
   Gitalist:
     file: lib/Gitalist.pm
-    version: 0.003001
+    version: 0.003002
   Gitalist::ActionRole::FilenameArgs:
     file: lib/Gitalist/ActionRole/FilenameArgs.pm
   Gitalist::ContentMangler::Resolver:
@@ -79,6 +79,8 @@ provides:
     file: lib/Gitalist/Git/Object/Tree.pm
   Gitalist::Git::Repository:
     file: lib/Gitalist/Git/Repository.pm
+  Gitalist::Git::Serializable:
+    file: lib/Gitalist/Git/Serializable.pm
   Gitalist::Git::Tag:
     file: lib/Gitalist/Git/Tag.pm
   Gitalist::Git::Types:
@@ -113,6 +115,7 @@ provides:
     file: lib/Gitalist/View/SyntaxHighlight.pm
 requires:
   CGI: 0
+  Catalyst::Action::REST: 0
   Catalyst::Action::RenderView: 0
   Catalyst::Component::InstancePerContext: 0
   Catalyst::Controller::ActionRole: 0
@@ -133,13 +136,16 @@ requires:
   Git::PurePerl: 0.47
   HTML::Entities: 0
   IPC::Run: 0
+  JSON: 0
   JSON::XS: 0
   List::MoreUtils: 0
   Moose: 0
   Moose::Autobox: 0
   MooseX::Declare: 0.32
+  MooseX::Storage: 0
   MooseX::Types: 0
   MooseX::Types::Common: 0
+  MooseX::Types::ISO8601: 0
   MooseX::Types::Path::Class: 0
   Path::Class: 0.17
   Syntax::Highlight::Engine::Kate: 0
@@ -154,4 +160,4 @@ resources:
   bugtracker: http://rt.cpan.org/Public/Dist/Display.html?Name=Gitalist
   license: http://opensource.org/licenses/gpl-2.0.php
   repository: git://git.shadowcat.co.uk/catagits/Gitalist.git
-version: 0.003001
+version: 0.003002
@@ -64,6 +64,7 @@ requires 'Catalyst::Plugin::Static::Simple';
 requires 'Catalyst::Plugin::Unicode::Encoding';
 requires 'Catalyst::Plugin::SubRequest' => '0.15';
 requires 'Catalyst::Action::RenderView';
+requires 'Catalyst::Action::REST';
 requires 'Catalyst::Component::InstancePerContext';
 requires 'Catalyst::Controller::ActionRole';
 requires 'Catalyst::View::Component::SubInclude' => '0.07';
@@ -78,9 +79,11 @@ requires 'Config::General';
 requires 'Moose';
 requires 'Moose::Autobox';
 requires 'MooseX::Declare' => '0.32';
+requires 'MooseX::Storage';
+requires 'MooseX::Types';
 requires 'MooseX::Types::Common';
 requires 'MooseX::Types::Path::Class';
-requires 'MooseX::Types';
+requires 'MooseX::Types::ISO8601';
 requires 'namespace::autoclean';
 
 requires 'Git::PurePerl' => '0.47';
@@ -94,6 +97,7 @@ requires 'File::Type::WebImages';
 requires 'File::Which';
 requires 'HTML::Entities';
 requires 'IPC::Run';
+requires 'JSON';
 requires 'JSON::XS';
 requires 'List::MoreUtils';
 requires 'Path::Class' => '0.17';
@@ -127,7 +131,7 @@ if ($ENV{GITALIST_RELEASE_TESTING}) {
     author_requires('WWW::Mechanize::TreeBuilder');
 }
 
-install_script glob('script/*.pl');
+install_script glob('script/*.p{l,sgi}');
 auto_install;
 
 {   # Make sure you REALLY REALLY have to have the env variable set to run
@@ -23,8 +23,8 @@ INSTALL
     repositories the directory above the checkout.
 
 DESCRIPTION
-    Gitalist is a web frontend for git repositories based on <gitweb.cgi>
-    and backed by Catalyst.
+    Gitalist is a web frontend for git repositories based on gitweb.cgi
+    <https://git.wiki.kernel.org/index.php/Gitweb> and backed by Catalyst.
 
   History
     This project started off as an attempt to port *gitweb.cgi* to a
@@ -122,8 +122,8 @@ RUNNING
     than using the single threaded developement server.
 
     The recommended deployment method for Gitalist is FastCGI, although
-    Gitalist can also be run under <mod_perl> or as pure Perl with
-    Catalyst::Engine::PreFork.
+    Gitalist can also be run under mod_perl <https://perl.apache.org/> or as
+    pure Perl with Catalyst::Engine::PreFork.
 
     Assuming that you have installed Gitalist's dependencies into a
     local::lib, and you are running from a git checkout, adding a trivial
@@ -137,6 +137,12 @@ RUNNING
 
         http://example.gitalist.com
 
+  Plack
+    If you would like to run Gitalist under Plack then one need only make
+    use of plackup and the ".psgi" found under "scripts/":
+
+        plackup script/gitalist_app.psgi
+
 CONFIGURATION
     The Gitalist config is loaded with Catalyst::Plugin::ConfigLoader and
     the available config options are:
@@ -173,11 +179,13 @@ CONFIGURATION
 
   FASTCGI
     Running Gitalist in FastCGI mode requires a webserver with FastCGI
-    support (such as apache with <mod_fcgi> or <mod_fcgid>). Below is a
-    sample configuration using Apache2 with mod_fcgid in a dynamic
-    configuration (as opposed to static or standalone mode). More
-    information on these modes and their configuration can be found at
-    "Standalone server mode" in Catalyst::Engine::FastCGI.
+    support (such as apache with mod_fcgi
+    <http://www.fastcgi.com/drupal/node/3> or mod_fcgid
+    <https://httpd.apache.org/mod_fcgid/>). Below is a sample configuration
+    using Apache2 with mod_fcgid in a dynamic configuration (as opposed to
+    static or standalone mode). More information on these modes and their
+    configuration can be found at "Standalone server mode" in
+    Catalyst::Engine::FastCGI.
 
     In Apache's mime.conf, add "AddHandler fcgid-script .fcgi" (or
     "AddHandler fastcgi-script .fcgi" for mod_fcgi).
@@ -204,7 +212,8 @@ CONFIGURATION
     Now to access your Gitalist instance, you'll go to
     "gitalist.yourdomain.com/gitalist.fcgi/" (do not forget that trailing
     "/"). If you'd like a different URL, of course, you'll likely want to
-    use <mod_rewrite> or equivalent.
+    use mod_rewrite <https://httpd.apache.org/docs/mod/mod_rewrite.html> or
+    equivalent.
 
     If you find the need to do some troubleshooting, you can call
     "http://url_to_gitalist.fcgi?dump_info=1" and/or add export
@@ -68,7 +68,16 @@ Provides some help for the search form.
 
 sub search_help : Chained('base') Args(0) {}
 
-sub end : ActionClass('RenderView') {}
+sub end : ActionClass('Serialize') {
+    my ($self, $c) = @_;
+    # Give repository views the current HEAD.
+    if ($c->stash->{Repository}) {
+        $c->stash->{HEAD} = $c->stash->{Repository}->head_hash;
+    }
+    if ($c->stash->{data} && blessed $c->stash->{data}) {
+        $c->stash->{rest} = $c->stash->{data}->pack;
+    }
+}
 
 sub error_404 : Action {
     my ($self, $c) = @_;
@@ -76,6 +85,16 @@ sub error_404 : Action {
     $c->response->body('Page not found');
 }
 
+__PACKAGE__->config(
+    default => 'text/html',
+    map => {
+        'application/json' => [qw/ JSON /],
+        map { $_ => [qw/ View Default /] }
+             qw( text/css text/html text/plain
+                 application/atom+xml application/rss+xml application/rss )
+    }
+);
+
 __PACKAGE__->meta->make_immutable;
 
 __END__
@@ -1,6 +1,6 @@
 use MooseX::Declare;
 
-role Gitalist::Git::CollectionOfRepositories {
+role Gitalist::Git::CollectionOfRepositories with Gitalist::Git::Serializable {
     use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
     use MooseX::Types::Moose qw/ArrayRef/;
     use Moose::Autobox;
@@ -21,6 +21,7 @@ role Gitalist::Git::HasUtils {
             get_gpp_object
             gpp
         /],
+        traits => ['DoNotSerialize']
     );
     method _build_util { confess(shift() . " cannot build _util") }
 }
@@ -1,11 +1,15 @@
 package Gitalist::Git::Head;
+
 use Moose;
 use namespace::autoclean;
 
-use Gitalist::Git::Types qw/SHA1/;
+with 'Gitalist::Git::Serializable';
+
 use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
-use MooseX::Types::DateTime;
-use DateTime;
+use MooseX::Types::Moose          qw/Maybe/;
+use Gitalist::Git::Types          qw/SHA1 DateTime/;
+
+use aliased 'DateTime' => 'DT';
 
 has sha1        => ( isa      => SHA1,
                      is       => 'ro',
@@ -19,10 +23,9 @@ has committer   => ( isa      => NonEmptySimpleStr,
                      is       => 'ro',
                      required => 1,
                  );
-has last_change => ( isa      => 'DateTime',
+has last_change => ( isa      => Maybe[DateTime],
                      is       => 'ro',
                      required => 1,
-                     coerce   => 1,
 );
 
 around BUILDARGS => sub {
@@ -38,7 +41,7 @@ around BUILDARGS => sub {
 
         my ($committer, $epoch, $tz) =
             $commitinfo =~ /(.*)\s(\d+)\s+([+-]\d+)$/;
-        my $dt = DateTime->from_epoch(
+        my $dt = DT->from_epoch(
             epoch => $epoch,
             time_zone => $tz,
         );
@@ -1,7 +1,9 @@
 use MooseX::Declare;
 use Moose::Autobox;
 
-class Gitalist::Git::Object is dirty {
+class Gitalist::Git::Object with Gitalist::Git::Serializable is dirty {
+    use MooseX::Storage::Meta::Attribute::Trait::DoNotSerialize;
+
     use MooseX::Types::Moose qw/Str Int Bool Maybe ArrayRef/;
     use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
     use overload '""' => '_to_string', fallback => 1;
@@ -32,11 +34,12 @@ class Gitalist::Git::Object is dirty {
                 lazy_build => 1 )
         for qw/modestr size/;
 
-    has _gpp_obj => ( isa => 'Git::PurePerl::Object',
-                      required => 1,
-                      is => 'ro',
+    has _gpp_obj => ( isa        => 'Git::PurePerl::Object',
+                      required   => 1,
+                      is         => 'ro',
                       lazy_build => 1,
-                      handles => [ 'content' ],
+                      handles    => [ 'content' ],
+                      traits     => ['DoNotSerialize']
                   );
 
     # objects can't determine their mode or filename
@@ -1,16 +1,18 @@
 use MooseX::Declare;
 
-class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
-    # FIXME, use Types::Path::Class and coerce
+class Gitalist::Git::Repository with (Gitalist::Git::HasUtils, Gitalist::Git::Serializable) {
+    use MooseX::Storage::Meta::Attribute::Trait::DoNotSerialize;
+
     use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
-    use MooseX::Types::Path::Class qw/Dir/;
-    use MooseX::Types::Moose qw/Str Maybe Bool HashRef ArrayRef/;
-    use Gitalist::Git::Types qw/SHA1/;
+    use MooseX::Types::Moose          qw/Str Maybe Bool HashRef ArrayRef/;
+    use Gitalist::Git::Types          qw/SHA1 DateTime Dir/;
+
     use Moose::Autobox;
+    use aliased 'DateTime' => 'DT';
     use List::MoreUtils qw/any zip/;
-    use DateTime;
-    use Encode qw/decode/;
-    use I18N::Langinfo qw/langinfo CODESET/;
+    use Encode          qw/decode/;
+    use I18N::Langinfo  qw/langinfo CODESET/;
+
     use Gitalist::Git::Object::Blob;
     use Gitalist::Git::Object::Tree;
     use Gitalist::Git::Object::Commit;
@@ -41,7 +43,8 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
                   is => 'ro', required => 1 );
 
     has path => ( isa => Dir,
-                  is => 'ro', required => 1);
+                  is => 'ro', required => 1,
+                  traits => ['DoNotSerialize'] );
 
     has description => ( isa => Str,
                          is => 'ro',
@@ -53,7 +56,7 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
                    lazy_build => 1,
                );
 
-    has last_change => ( isa => Maybe['DateTime'],
+    has last_change => ( isa => Maybe[DateTime],
                          is => 'ro',
                          lazy_build => 1,
                      );
@@ -233,7 +236,7 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
                 --sort=-committerdate --count=1 refs/heads
           });
         if (my ($epoch, $tz) = $output =~ /\s(\d+)\s+([+-]\d+)$/) {
-            my $dt = DateTime->from_epoch(epoch => $epoch);
+            my $dt = DT->from_epoch(epoch => $epoch);
             $dt->set_time_zone($tz);
             $last_change = $dt;
         }
@@ -0,0 +1,8 @@
+package Gitalist::Git::Serializable;
+
+use Moose::Role;
+use MooseX::Storage;
+
+with Storage( traits => ['OnlyWhenBuilt'] );
+
+1;
@@ -1,12 +1,15 @@
 package Gitalist::Git::Tag;
+
 use Moose;
 use namespace::autoclean;
 
-use Gitalist::Git::Types qw/SHA1/;
+with 'Gitalist::Git::Serializable';
+
 use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
-use MooseX::Types::Moose qw/Maybe Str/;
-use MooseX::Types::DateTime;
-use DateTime;
+use MooseX::Types::Moose          qw/Maybe/;
+use Gitalist::Git::Types          qw/SHA1 DateTime/;
+
+use aliased 'DateTime' => 'DT';
 
 has sha1        => ( isa      => SHA1,
                      is       => 'ro',
@@ -34,10 +37,9 @@ has committer   => ( isa      => NonEmptySimpleStr,
                      is       => 'ro',
                      required => 1,
                  );
-has last_change => ( isa      => 'DateTime',
+has last_change => ( isa      => Maybe[DateTime],
                      is       => 'ro',
                      required => 1,
-                     coerce   => 1,
 );
 
 around BUILDARGS => sub {
@@ -57,7 +59,7 @@ around BUILDARGS => sub {
         my ($subject, $commitinfo) = split /\0/, $rest, 2;
         my ($committer, $epoch, $tz) =
             $commitinfo =~ /(.*)\s(\d+)\s+([+-]\d+)$/;
-        my $dt = DateTime->from_epoch(
+        my $dt = DT->from_epoch(
             epoch => $epoch,
             time_zone => $tz,
         );
@@ -1,8 +1,16 @@
 package Gitalist::Git::Types;
 
 use MooseX::Types
-    -declare => [qw/SHA1/];
+     -declare => [qw/
+         SHA1
+         DateTime
+         Dir
+     /];
 
+use MooseX::Types::Path::Class;
+use MooseX::Types::ISO8601 qw/ISO8601DateTimeStr/;
+use MooseX::Types::DateTime ();
+use MooseX::Storage::Engine ();
 use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
 
 subtype SHA1,
@@ -14,4 +22,34 @@ coerce SHA1,
     from NonEmptySimpleStr,
     via { 1 };
 
+subtype DateTime,
+    as 'MooseX::Types::DateTime::DateTime',
+    where { 1 };
+
+MooseX::Storage::Engine->add_custom_type_handler(
+    DateTime,
+        expand   => sub {
+            my $val = shift;
+            Carp::confess("Not implemented");
+        },
+        collapse => sub {
+            to_ISO8601DateTimeStr(shift);
+        },
+);
+
+subtype Dir,
+    as 'MooseX::Types::Path::Class::Dir',
+    where { 1 };
+
+MooseX::Storage::Engine->add_custom_type_handler(
+    Dir,
+        expand   => sub {
+            my $val = shift;
+            Carp::confess("Not implemented");
+        },
+        collapse => sub {
+            shift() . '';
+        },
+);
+
 1;
@@ -14,7 +14,7 @@ use Catalyst qw/
                 SubRequest
 /;
 
-our $VERSION = '0.003001';
+our $VERSION = '0.003002';
 $VERSION = eval $VERSION;
 
 __PACKAGE__->config(
@@ -29,8 +29,13 @@ __PACKAGE__->setup();
 
 after prepare_path => sub {
     my ($ctx) = @_;
+    my $path = $ctx->req->uri->path;
     if ($ctx->req->param('a')) {
-        $ctx->request->uri->path('/legacy' . $ctx->request->uri->path);
+        $ctx->req->uri->path("/legacy$path");
+    }
+    
+    if($path =~ s/[.]json$// && $ctx->req->content_type eq 'application/json') {
+        $ctx->req->uri->path($path);
     }
 };
 
@@ -199,6 +204,14 @@ This example can be seen live here:
 
     http://example.gitalist.com
 
+=head2 Plack
+
+If you would like to run Gitalist under L<Plack> then one need only
+make use of L<plackup|search.cpan.org/perldoc?plackup> and the
+C<.psgi> found under C<scripts/>:
+
+    plackup script/gitalist_app.psgi
+
 =head1 CONFIGURATION
 
 The Gitalist config is loaded with L<Catalyst::Plugin::ConfigLoader>
@@ -1,4 +1,4 @@
-<h3>[% INCLUDE 'nav/path.tt2' %]</h3>
+<h3 class="header">[% INCLUDE 'nav/path.tt2' %]</h3>
 
   [% IF object.type == 'commit' %]
    <div class='commit-message'>
@@ -9,4 +9,4 @@
 [% subinclude('/fragment/ref/blob', c.req.captures, c.req.args.to_path) %]
 
 
- 
\ No newline at end of file
+ 
@@ -9,6 +9,12 @@
 </tr>
 [% END %]
 
+[% IF results.size == 0 %]
+<div class="copy">
+No results found for <q>[% c.req.param('text') | html %]</q>.
+</div>
+[% ELSE %]
+
 <table class='listing'>
 <thead>[% PROCESS shortlog_table_headfoot type = 'head' %]</thead>
 <tbody>
@@ -32,4 +38,6 @@
 </tr>
 [% END %]
 </tbody>
-</table>
\ No newline at end of file
+</table>
+
+[% END %]
@@ -1,4 +1,4 @@
-<h3>Search help</h3>
+<h3 class="header">Search help</h3>
 
 <div class="copy">
 <p><strong>Pattern</strong> is by default a normal string that is matched precisely (but without
@@ -51,7 +51,12 @@ a img{
 
 }
 #content_inner{
-    padding-bottom:30px;
+    padding-bottom:   30px;
+    background-color: white;
+    min-height:       100px;
+}
+.header {
+    background-color: #666;
 }
 .copy{
 	padding:10px;
@@ -0,0 +1,19 @@
+#!/usr/bin/perl
+
+use strict;
+
+use FindBin;
+BEGIN {
+    my $env = "$FindBin::Bin/env";
+    if (-r $env) {
+        do $env or die $@;
+    }
+}
+
+use Gitalist;
+use Plack::Builder;
+
+Gitalist->setup_engine('PSGI');
+my $app = sub { Gitalist->run(@_) };
+
+builder { $app };
@@ -83,3 +83,46 @@ my $owner = $proj->owner;
 is_flagged_utf8($owner, "Owner name is flagged as utf8");
 is_sane_utf8($owner, "Owner name is not double-encoded");
 is($owner, decode_utf8("T\x{c3}\x{a9}st"),  "Owner name is correct");
+
+is_deeply $proj->pack,  {
+    __CLASS__   => 'Gitalist::Git::Repository',
+    description => 'some test repository',
+    heads       => [
+        {
+            __CLASS__   => 'Gitalist::Git::Head',
+            committer   => 'Zachary Stevens <zts@cryptocracy.com>',
+            last_change => '2009-11-12T19:00:34Z',
+            name        => 'branch1',
+            sha1        => '0710a7c8ee11c73e8098d08f9384c2a839c65e4e'
+        },
+        {
+            __CLASS__   => 'Gitalist::Git::Head',
+            committer   => 'Florian Ragwitz <rafl@debian.org>',
+            last_change => '2007-03-06T20:44:35Z',
+            name        => 'master',
+            sha1        => '36c6c6708b8360d7023e8a1649c45bcf9b3bd818'
+        }
+    ],
+    is_bare     => 1,
+    last_change => '2009-11-12T19:00:34Z',
+    name        => 'repo1',
+    owner       => "T\351st",
+    references  => {
+        "36c6c6708b8360d7023e8a1649c45bcf9b3bd818" => [
+            'heads/master',
+            'tags/0.01'
+        ],
+        "0710a7c8ee11c73e8098d08f9384c2a839c65e4e" => [ 'heads/branch1' ]
+    },
+    tags        => [ {
+        __CLASS__
+             => 'Gitalist::Git::Tag',
+        committer
+             => 'Florian Ragwitz <rafl@debian.org>',
+        last_change
+             => '2007-03-06T20:44:35Z',
+        name    => 0.01,
+        sha1    => '36c6c6708b8360d7023e8a1649c45bcf9b3bd818',
+        type    => 'commit'
+    } ]
+}, 'Serialized correctly';
@@ -41,6 +41,27 @@ is($object->modestr, 'drwxr-xr-x', "modestr is correct" );
 is($object->size, 33, "size is correct");
 is($object,'729a7c3f6ba5453b42d16a43692205f67fb23bc1', 'stringifies correctly');
 
+is_deeply $object->pack, {
+    __CLASS__
+         => 'Gitalist::Git::Object::Tree',
+    file   => 'dir1',
+    mode   => 16384,
+    modestr
+         => 'drwxr-xr-x',
+    repository
+         => {
+             __CLASS__   => 'Gitalist::Git::Repository',
+             description => 'some test repository',
+             is_bare     => 1,
+             last_change => '2009-11-12T19:00:34Z',
+             name        => 'repo1',
+             owner       => 'Dan'
+         },
+    sha1   => '729a7c3f6ba5453b42d16a43692205f67fb23bc1',
+    size   => 33,
+    type   => 'tree'
+}, 'Serialized tree correctly';
+
 # Create object from sha1.
 my $obj2 = Gitalist::Git::Object::Blob->new(
     repository => $repository,
@@ -60,12 +81,72 @@ dies_ok {
     print $obj2->comment;
 } 'comment is an empty string';
 
+is_deeply $obj2->pack,  {
+    __CLASS__
+         => 'Gitalist::Git::Object::Blob',
+    mode   => 0,
+    modestr
+         => '----------',
+    repository
+         => {
+             __CLASS__   => 'Gitalist::Git::Repository',
+             description => 'some test repository',
+             is_bare     => 1,
+             last_change => '2009-11-12T19:00:34Z',
+             name        => 'repo1',
+             owner       => 'Dan'
+         },
+    sha1   => '5716ca5987cbf97d6bb54920bea6adde242d87e6',
+    size   => 4,
+    type   => 'blob'
+}, 'Serialized blob correctly';
+
 my $commit_obj = Gitalist::Git::Object::Commit->new(
     repository => $repository,
     sha1 => '3f7567c7bdf7e7ebf410926493b92d398333116e',
 );
 isa_ok($commit_obj, 'Gitalist::Git::Object::Commit', "commit object");
 isa_ok($commit_obj->tree->[0], 'Gitalist::Git::Object::Tree');
+
+is_deeply $commit_obj->pack,  {
+    __CLASS__
+         => 'Gitalist::Git::Object::Commit',
+    mode   => 0,
+    modestr
+         => '----------',
+    repository
+         => {
+             __CLASS__   => 'Gitalist::Git::Repository',
+             description => 'some test repository',
+             is_bare     => 1,
+             last_change => '2009-11-12T19:00:34Z',
+             name        => 'repo1',
+             owner       => 'Dan'
+         },
+    sha1   => '3f7567c7bdf7e7ebf410926493b92d398333116e',
+    size   => 218,
+    tree   => [ {
+        __CLASS__
+             => 'Gitalist::Git::Object::Tree',
+        mode   => 0,
+        modestr
+             => '----------',
+        repository
+             => {
+                 __CLASS__   => 'Gitalist::Git::Repository',
+                 description => 'some test repository',
+                 is_bare     => 1,
+                 last_change => '2009-11-12T19:00:34Z',
+                 name        => 'repo1',
+                 owner       => 'Dan'
+             },
+        sha1   => '9062594aebb5df0de7fb92413f17a9eced196c22',
+        size   => 33,
+        type   => 'tree'
+    } ],
+    type   => 'commit'
+}, 'Serialized commit correctly';
+
 my ($tree, $patch) = $commit_obj->diff(
     patch => 1,
 );
@@ -0,0 +1,39 @@
+#!/usr/bin/env perl
+
+use FindBin qw/$Bin/;
+BEGIN {
+    my $env = "$FindBin::Bin/../script/env";
+    if (-r $env) {
+        do $env or die $@;
+    }
+}
+
+use strict;
+use warnings;
+use Test::More;
+use HTTP::Request::Common;
+use JSON::XS qw/decode_json encode_json/;
+
+BEGIN {
+    $ENV{GITALIST_CONFIG} = $Bin;
+    $ENV{GITALIST_REPO_DIR} = '';
+    use_ok 'Catalyst::Test', 'Gitalist';
+}
+
+my $res = request(GET 'http://localhost/repo1', 'Content-Type' => 'application/json');
+is $res->code, 200;
+my $data = decode_json $res->content;
+is ref($data), 'HASH';
+delete $data->{owner}
+  if $data && exists $data->{owner};
+is_deeply $data, {
+          'is_bare' => 1,
+          '__CLASS__' => 'Gitalist::Git::Repository',
+          'last_change' => '2009-11-12T19:00:34Z',
+          'name' => 'repo1',
+          'description' => 'some test repository'
+        };
+
+done_testing;
+
+